﻿namespace NICWebApi.Extensions.JWT.Policy;

/*
 // custom provider which can return authorization policies for given
          // policy names (instead of using the default policy provider)
          services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();

          // As always, handlers must be provided for the requirements of the authorization policies
          services.AddSingleton<IAuthorizationHandler, MinimumAgeAuthorizationHandler>();
 */

internal class WebApiPolicyProvider : IAuthorizationPolicyProvider
{
    private const string POLICY_PREFIX = "WebAPI";
    public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }

    public WebApiPolicyProvider(IOptions<AuthorizationOptions> options)
    {
        // ASP.NET Core only uses one authorization policy provider, so if the custom implementation
        // doesn't handle all policies (including default policies, etc.) it should fall back to an
        // alternate provider.
        //
        // In this sample, a default authorization policy provider (constructed with options from the
        // dependency injection container) is used if this custom provider isn't able to handle a given
        // policy name.
        //
        // If a custom policy provider is able to handle all expected policy names then, of course, this
        // fallback pattern is unnecessary.
        FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
    }

    public Task<AuthorizationPolicy> GetDefaultPolicyAsync() => FallbackPolicyProvider.GetDefaultPolicyAsync();

    public Task<AuthorizationPolicy> GetFallbackPolicyAsync() => FallbackPolicyProvider.GetFallbackPolicyAsync();

    // Policies are looked up by string name, so expect 'parameters' (like age)
    // to be embedded in the policy names. This is abstracted away from developers
    // by the more strongly-typed attributes derived from AuthorizeAttribute
    // (like [WebApiRequirement] in this sample)
    public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
    {
        if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase))
        {
            //StringSplitOptions.RemoveEmptyEntries
            string[] splitStrings = policyName.Substring(POLICY_PREFIX.Length).Split('_');
            if (int.TryParse(splitStrings[0], out int roleid) && splitStrings.Length > 3)
            {
                var policy = new AuthorizationPolicyBuilder();
                policy.AddRequirements(new WebApiRequirement(roleid, splitStrings[1], splitStrings[2]));
                return Task.FromResult(policy.Build());
            }
            else
            {
                var policy = new AuthorizationPolicyBuilder();
                policy.AddRequirements(new WebApiRequirement(-1, policyName));
                return Task.FromResult(policy.Build());
            }
        }

        // If the policy name doesn't match the format expected by this policy provider,
        // try the fallback provider. If no fallback provider is used, this would return
        // Task.FromResult<AuthorizationPolicy>(null) instead.
        return FallbackPolicyProvider.GetPolicyAsync(policyName);
    }
}